﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace PersonaLibrary.Data
{
    /// <summary>
    /// Using for display only
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public sealed class EventsEntitySet<T> : IEnumerable<T>, INotifyCollectionChanged, IDisposable
        where T : BaseEntity
    {
        internal readonly ObservableCollection<T> Collection;

        public EventsEntitySet()
        {
            Collection = new ObservableCollection<T>();
            onCreated();
            EntityAddedFilter = x => true;
        }

        public EventsEntitySet(IEnumerable<T> arg)
        {
            Collection = new ObservableCollection<T>(arg);
            onCreated();
            LinqToDbDataContext.ItemAdded += LinqToDbDataContext_ItemAdded;
            LinqToDbDataContext.ItemDeleted += LinqToDbDataContext_ItemDeleted;
            LinqToDbDataContext.ItemUpdated += LinqToDbDataContext_ItemUpdated;
        }

        public Func<T, bool> EntityAddedFilter { set; get; }

        void collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            riseCollectionChanged(e);
        }

        private void onCreated()
        {
            Collection.CollectionChanged += collection_CollectionChanged;

        }

        private void riseCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null) 
                CollectionChanged(this, e);
        }

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        public IEnumerator<T> GetEnumerator()
        {
            return Collection.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Collection.GetEnumerator();
        }

        void LinqToDbDataContext_ItemUpdated(BaseEntity obj)
        {
            if (obj is T &&  Collection.Any(x => x.Id == obj.Id))
            {
                var original = Collection.Single(x => x.Id == obj.Id);
                int index = Collection.IndexOf(original);
                Collection[index] = (T)obj;
            }
        }

        void LinqToDbDataContext_ItemDeleted(BaseEntity obj)
        {
			if (obj is T && Collection.Any(x => x.Id == obj.Id))
            {
                Collection.Remove(Collection.Single(x => x.Id == obj.Id));
            }
        }

        void LinqToDbDataContext_ItemAdded(BaseEntity obj)
        {
            if (obj is T && EntityAddedFilter.Invoke((T)obj) && Collection.All(x => x.Id != obj.Id))
            {
				Collection.Add((T)obj);
            }
        }

        public void Dispose()
        {
            LinqToDbDataContext.ItemAdded -= LinqToDbDataContext_ItemAdded;
            LinqToDbDataContext.ItemDeleted -= LinqToDbDataContext_ItemDeleted;
            LinqToDbDataContext.ItemUpdated -= LinqToDbDataContext_ItemUpdated;
        }
    }
}
